using Digitalmes.Domain.Entities.Mes.Processes;

namespace Digitalmes.Application.Mes.Processes.RoutingSteps.Commands;

/// <summary>
/// 工艺路线步骤向下排序命令。
/// </summary>
public sealed record DownSortRoutingStepCommand(long RoutingStepId) : IRequest<IResult<bool>>;

internal sealed class DownSortRoutingStepCommandHandler(IRepository<ProcRoutingStep> repo) : IRequestHandler<DownSortRoutingStepCommand, IResult<bool>>
{
    public async Task<IResult<bool>> Handle(DownSortRoutingStepCommand request, CancellationToken cancellationToken)
    {
        var step = await repo.GetByIdAsync(request.RoutingStepId, cancellationToken);
        if (step == null)
        {
            return Result.From(true);
        }

        // 尾部序
        if (step.NextStepId is null)
        {
            return Result.From(true);
        }

        // 交换
        // A -> B -> C -> D
        // B 与 C 交换，A.next = C; B.prev = D; B.next = D; C.prev = A; C.next = B; 
        var nextStep = await repo.FirstOrDefaultAsync(m => m.PrevStepId == step.Id, cancellationToken);
        if (nextStep == null)
        {
            return Result.From(true);
        }

        List<ProcRoutingStep> steps = [step, nextStep];
        (step.Seq, nextStep.Seq) = (nextStep.Seq, step.Seq); // 交换 seq

        // B <=> D
        if (nextStep.NextStepId is not null)
        {
            var nextStep2 = await repo.FirstOrDefaultAsync(m => m.PrevStepId == nextStep.Id, cancellationToken);
            if (nextStep2 != null)
            {
                nextStep2.PrevStepId = step.Id;
                steps.Add(nextStep2);
            }
        }

        // C <=> A
        var prevStep = await repo.FirstOrDefaultAsync(m => m.NextStepId == step.Id, cancellationToken);
        if (prevStep != null)
        {
            prevStep.NextStepId = nextStep.Id;
            steps.Add(nextStep);
        }

        // B <=> C
        step.NextStepId = nextStep.NextStepId;
        nextStep.PrevStepId = step.PrevStepId;
        nextStep.NextStepId = step.Id;
        step.PrevStepId = nextStep.Id;

        var ok = await repo.UpdateAsync(steps, m => new
        {
            m.Seq,
            m.PrevStepId,
            m.NextStepId,
            m.UpdatedBy,
            m.UpdatedTime,
        }, cancellationToken);
        return Result.From(ok);
    }
}
